#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 * 联合体/共用体
 * 定义:
 *  union 名称
 *  {
 *      成员变量1;
 *      ···
 *      成员变量n;
 *  };
 *
 * 内存布局:
 *  成员变量的存储: 所有成员变量共用一块内存空间
 *  大小: 成员变量中占用内存空间最大的变量的大小
 *
 *
 */
int main() {
    union union1 {
        char ch[4];
        int x;
    };
    union union2 {
        char ch[2];
        unsigned short x;
    };
    printf("共用体占用的内存空间: %d字节\n", sizeof(union union1));
    printf("共用体占用的内存空间: %d字节\n", sizeof(union union2));
    //实际使用:
    //场景1、已知一个整型变量的值，求出这个变量每一个字节的值。
    union union1 u1;
    u1.x = 0x01020304;
    //由于共用的缘故，所以在为x赋值的时候，组成x的每一个字节的值就已经保存在了ch数组里面了
    printf("共用体union1的ch数组的每一个字节保存的值: ");
    for (int i = 0; i < sizeof(u1.ch); ++i) {
        printf("%d ", u1.ch[i]);
    }
    //场景2、传感器GY39可以测量出温度、湿度、大气压强、海拔，假设我们自己开发一个设备以连接GY39模块，GY39回复的数据格式如下:
    // 其中各参数计算公式:
    //  温度——arr[2]<<8 | arr[3]
    //  湿度——arr[4]<<8 | arr[5]
    //  大气压强——arr[6]<<24 | arr[7]<<16 | arr[8]<<8 | arr[9]
    //  海拔——arr[10]<<24 | arr[11]<<16 | arr[12]<<8 | arr[13]
    char arr[16] = {0x5a, 0x5a, 0x01, 0x02, 0x03, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x02, 0x03, 0x04, 0x5a, 0x5a};
    //比如我希望可以使用联合体求温度
    union union2 u2;
    u2.ch[0] = arr[3];
    u2.ch[1] = arr[2];
    //则现在的成员变量x就是温度的值!
    printf("\n共用体union2求出的温度值: %d\n", u2.x);

    //小端模式和大端模式
    // 数据在内存中以二进制形式存储，但是如果数据占用内存空间超过1字节，我们也可以理解为该数据在内存中是以一个字节一个字节的存储。
    // 那么对于例如一个int类型的变量，它占4个字节，那么这4个字节存储的值分别是多少呢?在上面其实我们也已经演示过了
    printf("共用体union1的ch数组的每一个字节保存的值以及对应的地址: ");
    for (int i = 0; i < sizeof(u1.ch); ++i) {
        printf("%x->%p ", u1.ch[i], &u1.ch[i]);
    }
    printf("\n");
    //根据程序运行结构我们可以得出结论:低字节的数据是存储在低地址，高字节的数据存储在高地址。这种存储模式我们称之为"小端模式"。
    // 同理，如果低字节的数据是存储在高地址，高字节的数据存储在低地址，则我们称之为"大端模式"。
    // 计算机的大端模式和小端模式跟操作系统没有关系!跟CPU有关系。目前大部分处理器都采用小端模式，只有部分嵌入式处理器采用大端或者可自行设置。

    //场景3、测试某个处理器是大端模式还是小端模式
    u2.x = 0x0102;
    if (u2.ch[0] == 0x02) printf("小端模式\n");
    else printf("大端模式\n");


    return 0;

}